﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SharpAnalyzer.Entities;
using SharpAnalyzer.Utilities;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace SharpAnalyzer.Analyzers
{
    internal sealed class CyclomaticComplexityAnalyzer : CSharpSyntaxWalker
    {
        private int counter = 1;

        public CyclomaticComplexityAnalyzer()
          : base(SyntaxWalkerDepth.Node)
        {
        }

        public int Calculate(Member node)
        {
            Verify.NotNull(() => node);

            BlockSyntax body = MemberBodySelector.FindBody(node);
            if (body != null)
                Visit(body);
            return checked(counter + CalculateLogicalComplexity(node));
        }

        private static int CalculateLogicalComplexity(Member node)
        {
            return new LogicalComplexityAnalyzer().Calculate(node);
        }

        public override void VisitIfStatement(IfStatementSyntax node)
        {
            base.VisitIfStatement(node);
            checked { ++counter; }
        }

        public override void VisitConditionalExpression(ConditionalExpressionSyntax node)
        {
            base.VisitConditionalExpression(node);
            if (node.QuestionToken.Kind() != SyntaxKind.QuestionToken || node.ColonToken.Kind() != SyntaxKind.ColonToken)
                return;
            checked { ++counter; }
        }

        public override void VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            base.VisitBinaryExpression(node);
            if (node.OperatorToken.Kind() != SyntaxKind.QuestionQuestionToken)
                return;
            checked { ++counter; }
        }

        public override void VisitElseClause(ElseClauseSyntax node)
        {
            base.VisitElseClause(node);
            checked { ++counter; }
        }

        public override void VisitInitializerExpression(InitializerExpressionSyntax node)
        {
            base.VisitInitializerExpression(node);
            checked { ++counter; }
        }

        public override void VisitSwitchSection(SwitchSectionSyntax node)
        {
            base.VisitSwitchSection(node);
            checked { ++counter; }
        }

        public override void VisitWhileStatement(WhileStatementSyntax node)
        {
            base.VisitWhileStatement(node);
            checked { ++counter; }
        }

        public override void VisitDoStatement(DoStatementSyntax node)
        {
            base.VisitDoStatement(node);
            checked { ++counter; }
        }

        public override void VisitForEachStatement(ForEachStatementSyntax node)
        {
            base.VisitForEachStatement(node);
            checked { ++counter; }
        }

        public override void VisitForStatement(ForStatementSyntax node)
        {
            base.VisitForStatement(node);
            checked { ++counter; }
        }
    }
}
